(* Tests for the [Fifo] module. We speak about a [classic] and [showahead] fifo which
   differ in when the output data appears. In classic mode it is 1 cycle after a read,
   while in showahead mode it is valid along with the empty flags deassertion. *)

open! Import
open Hardcaml_waveterm_kernel
open Hardcaml_waveterm_cyclesim

module I = struct
  type 'a t =
    { clock : 'a
    ; clear : 'a
    ; wr : 'a
    ; d : 'a [@bits 32]
    ; rd : 'a
    }
  [@@deriving hardcaml]
end

let used_bits = 3

module O = struct
  type 'a t =
    { q : 'a [@bits 32]
    ; full : 'a
    ; empty : 'a
    ; nearly_full : 'a
    ; nearly_empty : 'a
    ; used : 'a [@bits used_bits]
    }
  [@@deriving hardcaml]
end

open Hardcaml

let wrap ?(capacity = 4) ~create_fn (i : _ I.t) =
  let open Signal in
  assert (num_bits_to_represent capacity <= used_bits);
  let { Fifo.q
      ; full
      ; empty
      ; nearly_full
      ; nearly_empty
      ; used
      ; wr_rst_busy = _
      ; rd_rst_busy = _
      }
    =
    create_fn ~capacity ~clock:i.clock ~clear:i.clear ~wr:i.wr ~d:i.d ~rd:i.rd
  in
  let o =
    { O.q; full; empty; nearly_full; nearly_empty; used = uresize used ~width:used_bits }
  in
  o
;;

let display_rules =
  Display_rule.(
    [ I.map I.port_names ~f:(port_name_is ~wave_format:(Bit_or Unsigned_int)) |> I.to_list
    ; O.map O.port_names ~f:(port_name_is ~wave_format:(Bit_or Unsigned_int)) |> O.to_list
    ; [ port_name_matches Re.Posix.(re ".*" |> compile) ~wave_format:(Bit_or Unsigned_int)
      ]
    ]
    |> List.concat)
;;

let fill_then_empty ?(wave_width = 1) (waves, sim) =
  let inputs : _ I.t = Cyclesim.inputs sim in
  let outputs : _ O.t = Cyclesim.outputs sim in
  inputs.clear := Bits.vdd;
  Cyclesim.cycle sim;
  inputs.clear := Bits.gnd;
  inputs.wr := Bits.vdd;
  let rec write i =
    if not (Bits.to_bool !(outputs.full))
    then (
      inputs.d := Bits.of_int_trunc ~width:32 ((i + 1) * 10);
      Cyclesim.cycle sim;
      write (i + 1))
    else i
  in
  let wr_count = write 0 in
  inputs.wr := Bits.gnd;
  inputs.d := Bits.of_int_trunc ~width:32 0;
  Cyclesim.cycle sim;
  inputs.rd := Bits.vdd;
  let rd_count = ref 0 in
  let timeout = ref 100 in
  while !rd_count <> wr_count && !timeout <> 0 do
    if not (Bits.to_bool !(outputs.empty)) then Int.incr rd_count;
    Cyclesim.cycle sim;
    Int.decr timeout
  done;
  inputs.rd := Bits.gnd;
  Cyclesim.cycle sim;
  Cyclesim.cycle sim;
  Waveform.print ~display_width:87 ~wave_width ~display_rules waves
;;

let%expect_test "classic" =
  let module Sim = Cyclesim.With_interface (I) (O) in
  wrap ~create_fn:(Fifo.create ~showahead:false ())
  |> Sim.create
  |> Waveform.create
  |> fill_then_empty;
  [%expect
    {|
    ┌Signals───────────┐┌Waves────────────────────────────────────────────────────────────┐
    │clock             ││┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌│
    │                  ││  └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘│
    │clear             ││────┐                                                            │
    │                  ││    └───────────────────────────────────────────                 │
    │wr                ││    ┌───────────────┐                                            │
    │                  ││────┘               └───────────────────────────                 │
    │                  ││────┬───┬───┬───┬───┬───────────────────────────                 │
    │d                 ││ 0  │10 │20 │30 │40 │0                                           │
    │                  ││────┴───┴───┴───┴───┴───────────────────────────                 │
    │rd                ││                        ┌───────────────┐                        │
    │                  ││────────────────────────┘               └───────                 │
    │                  ││────────────────────────────┬───┬───┬───┬───────                 │
    │q                 ││ 0                          │10 │20 │30 │40                      │
    │                  ││────────────────────────────┴───┴───┴───┴───────                 │
    │full              ││                    ┌───────┐                                    │
    │                  ││────────────────────┘       └───────────────────                 │
    │empty             ││────────┐                               ┌───────                 │
    │                  ││        └───────────────────────────────┘                        │
    │nearly_full       ││                ┌───────────────┐                                │
    │                  ││────────────────┘               └───────────────                 │
    │nearly_empty      ││────────────┐                       ┌───────────                 │
    │                  ││            └───────────────────────┘                            │
    │                  ││────────┬───┬───┬───┬───────┬───┬───┬───┬───────                 │
    │used              ││ 0      │1  │2  │3  │4      │3  │2  │1  │0                       │
    │                  ││────────┴───┴───┴───┴───────┴───┴───┴───┴───────                 │
    └──────────────────┘└─────────────────────────────────────────────────────────────────┘
    |}]
;;

let%expect_test "showahead" =
  let module Sim = Cyclesim.With_interface (I) (O) in
  wrap ~create_fn:(Fifo.create ~showahead:true ())
  |> Sim.create
  |> Waveform.create
  |> fill_then_empty;
  [%expect
    {|
    ┌Signals───────────┐┌Waves────────────────────────────────────────────────────────────┐
    │clock             ││┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌│
    │                  ││  └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘│
    │clear             ││────┐                                                            │
    │                  ││    └───────────────────────────────────────────────────         │
    │wr                ││    ┌───────────────────┐                                        │
    │                  ││────┘                   └───────────────────────────────         │
    │                  ││────┬───┬───┬───┬───┬───┬───────────────────────────────         │
    │d                 ││ 0  │10 │20 │30 │40 │50 │0                                       │
    │                  ││────┴───┴───┴───┴───┴───┴───────────────────────────────         │
    │rd                ││                            ┌───────────────────┐                │
    │                  ││────────────────────────────┘                   └───────         │
    │                  ││────────┬───────────────────────┬───┬───┬───┬───┬───────         │
    │q                 ││ 0      │10                     │20 │30 │40 │50 │20              │
    │                  ││────────┴───────────────────────┴───┴───┴───┴───┴───────         │
    │full              ││                        ┌───────┐                                │
    │                  ││────────────────────────┘       └───────────────────────         │
    │empty             ││────────┐                                       ┌───────         │
    │                  ││        └───────────────────────────────────────┘                │
    │nearly_full       ││                    ┌───────────────┐                            │
    │                  ││────────────────────┘               └───────────────────         │
    │nearly_empty      ││────────────┐                               ┌───────────         │
    │                  ││            └───────────────────────────────┘                    │
    │                  ││────────┬───┬───┬───┬───┬───────┬───┬───┬───┬───┬───────         │
    │used              ││ 0      │1  │2  │3  │4  │5      │4  │3  │2  │1  │0               │
    │                  ││────────┴───┴───┴───┴───┴───────┴───┴───┴───┴───┴───────         │
    └──────────────────┘└─────────────────────────────────────────────────────────────────┘
    |}]
;;

let%expect_test "classic with reg" =
  let module Sim = Cyclesim.With_interface (I) (O) in
  wrap ~create_fn:(Fifo.create_classic_with_extra_reg ())
  |> Sim.create
  |> Waveform.create
  |> fill_then_empty;
  [%expect
    {|
    ┌Signals───────────┐┌Waves────────────────────────────────────────────────────────────┐
    │clock             ││┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌│
    │                  ││  └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘│
    │clear             ││────┐                                                            │
    │                  ││    └─────────────────────────────────────────────────────────── │
    │wr                ││    ┌───────────────────────┐                                    │
    │                  ││────┘                       └─────────────────────────────────── │
    │                  ││────┬───┬───┬───┬───┬───┬───┬─────────────────────────────────── │
    │d                 ││ 0  │10 │20 │30 │40 │50 │60 │0                                   │
    │                  ││────┴───┴───┴───┴───┴───┴───┴─────────────────────────────────── │
    │rd                ││                                ┌───────────────────────┐        │
    │                  ││────────────────────────────────┘                       └─────── │
    │                  ││────────────────────────────────────┬───┬───┬───┬───┬───┬─────── │
    │q                 ││ 0                                  │10 │20 │30 │40 │50 │60      │
    │                  ││────────────────────────────────────┴───┴───┴───┴───┴───┴─────── │
    │full              ││                            ┌───────────┐                        │
    │                  ││────────────────────────────┘           └─────────────────────── │
    │empty             ││────────────┐                                           ┌─────── │
    │                  ││            └───────────────────────────────────────────┘        │
    │nearly_full       ││                        ┌───────────────────┐                    │
    │                  ││────────────────────────┘                   └─────────────────── │
    │nearly_empty      ││────────────────────┐                           ┌─────────────── │
    │                  ││                    └───────────────────────────┘                │
    │                  ││────────┬───────────┬───┬───┬───────────┬───┬───┬───┬─────────── │
    │used              ││ 0      │1          │2  │3  │4          │3  │2  │1  │0           │
    │                  ││────────┴───────────┴───┴───┴───────────┴───┴───┴───┴─────────── │
    └──────────────────┘└─────────────────────────────────────────────────────────────────┘
    |}]
;;

let%expect_test "showahead from classic" =
  let module Sim = Cyclesim.With_interface (I) (O) in
  wrap ~create_fn:(Fifo.create_showahead_from_classic ())
  |> Sim.create
  |> Waveform.create
  |> fill_then_empty;
  [%expect
    {|
    ┌Signals───────────┐┌Waves────────────────────────────────────────────────────────────┐
    │clock             ││┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌│
    │                  ││  └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘│
    │clear             ││────┐                                                            │
    │                  ││    └───────────────────────────────────────────────────         │
    │wr                ││    ┌───────────────────┐                                        │
    │                  ││────┘                   └───────────────────────────────         │
    │                  ││────┬───┬───┬───┬───┬───┬───────────────────────────────         │
    │d                 ││ 0  │10 │20 │30 │40 │50 │0                                       │
    │                  ││────┴───┴───┴───┴───┴───┴───────────────────────────────         │
    │rd                ││                            ┌───────────────────┐                │
    │                  ││────────────────────────────┘                   └───────         │
    │                  ││────────────┬───────────────────┬───┬───┬───┬───────────         │
    │q                 ││ 0          │10                 │20 │30 │40 │50                  │
    │                  ││────────────┴───────────────────┴───┴───┴───┴───────────         │
    │full              ││                        ┌───────┐                                │
    │                  ││────────────────────────┘       └───────────────────────         │
    │empty             ││────────────┐                                   ┌───────         │
    │                  ││            └───────────────────────────────────┘                │
    │nearly_full       ││                    ┌───────────────┐                            │
    │                  ││────────────────────┘               └───────────────────         │
    │nearly_empty      ││────────────────┐                       ┌───────────────         │
    │                  ││                └───────────────────────┘                        │
    │                  ││────────┬───────┬───┬───┬───────┬───┬───┬───┬───────────         │
    │used              ││ 0      │1      │2  │3  │4      │3  │2  │1  │0                   │
    │                  ││────────┴───────┴───┴───┴───────┴───┴───┴───┴───────────         │
    └──────────────────┘└─────────────────────────────────────────────────────────────────┘
    |}]
;;

let%expect_test "showahead with extra reg" =
  let module Sim = Cyclesim.With_interface (I) (O) in
  wrap ~create_fn:(Fifo.create_showahead_with_extra_reg ())
  |> Sim.create
  |> Waveform.create
  |> fill_then_empty;
  [%expect
    {|
    ┌Signals───────────┐┌Waves────────────────────────────────────────────────────────────┐
    │clock             ││┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌│
    │                  ││  └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘│
    │clear             ││────┐                                                            │
    │                  ││    └───────────────────────────────────────────                 │
    │wr                ││    ┌───────────────┐                                            │
    │                  ││────┘               └───────────────────────────                 │
    │                  ││────┬───┬───┬───┬───┬───────────────────────────                 │
    │d                 ││ 0  │10 │20 │30 │40 │0                                           │
    │                  ││────┴───┴───┴───┴───┴───────────────────────────                 │
    │rd                ││                        ┌───────────────┐                        │
    │                  ││────────────────────────┘               └───────                 │
    │                  ││────────────────┬───────────┬───┬───┬───────────                 │
    │q                 ││ 0              │10         │20 │30 │40                          │
    │                  ││────────────────┴───────────┴───┴───┴───────────                 │
    │full              ││                    ┌───────┐                                    │
    │                  ││────────────────────┘       └───────────────────                 │
    │empty             ││────────────────┐                       ┌───────                 │
    │                  ││                └───────────────────────┘                        │
    │nearly_full       ││                ┌───────────────┐                                │
    │                  ││────────────────┘               └───────────────                 │
    │nearly_empty      ││────────────┐                       ┌───────────                 │
    │                  ││            └───────────────────────┘                            │
    │                  ││────────┬───┬───┬───┬───────┬───┬───┬───┬───────                 │
    │used              ││ 0      │1  │2  │3  │4      │3  │2  │1  │0                       │
    │                  ││────────┴───┴───┴───┴───────┴───┴───┴───┴───────                 │
    └──────────────────┘└─────────────────────────────────────────────────────────────────┘
    |}]
;;

let%expect_test "non-default nearly empty/full threshold values" =
  let module Sim = Cyclesim.With_interface (I) (O) in
  wrap ~create_fn:(Fifo.create ~showahead:true ~nearly_empty:2 ~nearly_full:1 ())
  |> Sim.create
  |> Waveform.create
  |> fill_then_empty;
  [%expect
    {|
    ┌Signals───────────┐┌Waves────────────────────────────────────────────────────────────┐
    │clock             ││┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌│
    │                  ││  └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘│
    │clear             ││────┐                                                            │
    │                  ││    └───────────────────────────────────────────────────         │
    │wr                ││    ┌───────────────────┐                                        │
    │                  ││────┘                   └───────────────────────────────         │
    │                  ││────┬───┬───┬───┬───┬───┬───────────────────────────────         │
    │d                 ││ 0  │10 │20 │30 │40 │50 │0                                       │
    │                  ││────┴───┴───┴───┴───┴───┴───────────────────────────────         │
    │rd                ││                            ┌───────────────────┐                │
    │                  ││────────────────────────────┘                   └───────         │
    │                  ││────────┬───────────────────────┬───┬───┬───┬───┬───────         │
    │q                 ││ 0      │10                     │20 │30 │40 │50 │20              │
    │                  ││────────┴───────────────────────┴───┴───┴───┴───┴───────         │
    │full              ││                        ┌───────┐                                │
    │                  ││────────────────────────┘       └───────────────────────         │
    │empty             ││────────┐                                       ┌───────         │
    │                  ││        └───────────────────────────────────────┘                │
    │nearly_full       ││        ┌───────────────────────────────────────┐                │
    │                  ││────────┘                                       └───────         │
    │nearly_empty      ││────────────────┐                       ┌───────────────         │
    │                  ││                └───────────────────────┘                        │
    │                  ││────────┬───┬───┬───┬───┬───────┬───┬───┬───┬───┬───────         │
    │used              ││ 0      │1  │2  │3  │4  │5      │4  │3  │2  │1  │0               │
    │                  ││────────┴───┴───┴───┴───┴───────┴───┴───┴───┴───┴───────         │
    └──────────────────┘└─────────────────────────────────────────────────────────────────┘
    |}]
;;

let%expect_test "showahead with read_latency" =
  let module Sim = Cyclesim.With_interface (I) (O) in
  wrap ~capacity:3 ~create_fn:(Fifo.create_showahead_with_read_latency ~read_latency:5 ())
  |> Sim.create
  |> Waveform.create
  |> fill_then_empty ~wave_width:0;
  [%expect
    {|
    ┌Signals───────────┐┌Waves────────────────────────────────────────────────────────────┐
    │clock             ││┌┐┌┐┌┐┌┐┌┐┌┐┌┐┌┐┌┐┌┐┌┐┌┐┌┐┌┐┌┐┌┐┌┐┌┐┌┐┌┐┌┐┌┐┌┐┌┐┌┐┌┐┌┐┌┐┌┐┌┐┌┐┌┐┌│
    │                  ││ └┘└┘└┘└┘└┘└┘└┘└┘└┘└┘└┘└┘└┘└┘└┘└┘└┘└┘└┘└┘└┘└┘└┘└┘└┘└┘└┘└┘└┘└┘└┘└┘│
    │clear             ││──┐                                                              │
    │                  ││  └───────────────────────────────────────────                   │
    │wr                ││  ┌─────┐                                                        │
    │                  ││──┘     └─────────────────────────────────────                   │
    │                  ││──┬─┬─┬─┬─────────────────────────────────────                   │
    │d                 ││ 0│.│.│.│0                                                       │
    │                  ││──┴─┴─┴─┴─────────────────────────────────────                   │
    │rd                ││          ┌───────────────────────────────┐                      │
    │                  ││──────────┘                               └───                   │
    │                  ││────────────────┬───────────┬───────────┬─────                   │
    │q                 ││ 0              │10         │20         │30                      │
    │                  ││────────────────┴───────────┴───────────┴─────                   │
    │full              ││        ┌─────────┐                                              │
    │                  ││────────┘         └───────────────────────────                   │
    │empty             ││────────────────┐ ┌─────────┐ ┌─────────┐ ┌───                   │
    │                  ││                └─┘         └─┘         └─┘                      │
    │nearly_full       ││        ┌─────────┐                                              │
    │                  ││────────┘         └───────────────────────────                   │
    │nearly_empty      ││──────┐                       ┌───────────────                   │
    │                  ││      └───────────────────────┘                                  │
    │                  ││────┬─┬─┬─────────┬───────────┬───────────┬───                   │
    │used              ││ 0  │1│2│3        │2          │1          │0                     │
    │                  ││────┴─┴─┴─────────┴───────────┴───────────┴───                   │
    └──────────────────┘└─────────────────────────────────────────────────────────────────┘
    |}]
;;

module%test Typed_tests = struct
  module Data_entry = struct
    type 'a t =
      { field_a : 'a [@bits 16]
      ; field_b : 'a [@bits 16]
      }
    [@@deriving hardcaml]
  end

  module I = struct
    type 'a t =
      { clock : 'a
      ; clear : 'a
      ; wr : 'a
      ; a : 'a [@bits 16]
      ; b : 'a [@bits 16]
      ; rd : 'a
      }
    [@@deriving hardcaml]
  end

  let used_bits = 3

  module O = struct
    type 'a t =
      { valid : 'a
      ; q_field_a : 'a [@bits 16]
      ; q_field_b : 'a [@bits 16]
      ; full : 'a
      ; empty : 'a
      ; overflow : 'a
      ; read_when_empty : 'a
      }
    [@@deriving hardcaml]
  end

  let wrap ~cut_through ?(capacity = 4) (i : _ I.t) =
    let open Signal in
    assert (num_bits_to_represent capacity <= used_bits);
    let { Fifo.q; full; empty; overflow; read_when_empty } =
      (if cut_through then Fifo.cut_through_typed_fifo else Fifo.typed_fifo)
        (module Data_entry)
        ~capacity
        ~clocking:{ clock = i.clock; clear = i.clear }
        ~input:{ valid = i.wr; value = { Data_entry.field_a = i.a; field_b = i.b } }
        ~read:i.rd
    in
    let o =
      { O.valid = q.valid
      ; q_field_a = q.value.field_a
      ; q_field_b = q.value.field_b
      ; full
      ; empty
      ; overflow
      ; read_when_empty
      }
    in
    o
  ;;

  let fill_while_reading ?(wave_width = 1) (waves, sim) =
    let inputs : _ I.t = Cyclesim.inputs sim in
    inputs.clear := Bits.vdd;
    Cyclesim.cycle sim;
    inputs.clear := Bits.gnd;
    inputs.wr := Bits.vdd;
    inputs.rd := Bits.vdd;
    let rec write i =
      if i < 10
      then (
        inputs.a := Bits.of_int_trunc ~width:16 ((i + 1) * 10);
        inputs.b := Bits.of_int_trunc ~width:16 (150 - ((i + 1) * 10));
        Cyclesim.cycle sim;
        write (i + 1))
      else ()
    in
    write 0;
    inputs.wr := Bits.gnd;
    inputs.a := Bits.of_int_trunc ~width:16 0;
    inputs.b := Bits.of_int_trunc ~width:16 0;
    (* The typed fifo currently does not handle read delays so we don't need to worry
       about counting reads, they should all flush in a few cycles. *)
    Cyclesim.cycle ~n:3 sim;
    Waveform.print ~display_width:87 ~wave_width ~display_rules waves
  ;;

  (* This is a copy of the previous fill_then_empty method modified to accept the new
     I.t and O.t. *)
  let fill_then_empty ?(wave_width = 1) (waves, sim) =
    let inputs : _ I.t = Cyclesim.inputs sim in
    let outputs : _ O.t = Cyclesim.outputs sim in
    inputs.clear := Bits.vdd;
    Cyclesim.cycle sim;
    inputs.clear := Bits.gnd;
    inputs.wr := Bits.vdd;
    let rec write i =
      if not (Bits.to_bool !(outputs.full))
      then (
        inputs.a := Bits.of_int_trunc ~width:16 ((i + 1) * 10);
        inputs.b := Bits.of_int_trunc ~width:16 (150 - ((i + 1) * 10));
        Cyclesim.cycle sim;
        write (i + 1))
      else i
    in
    let wr_count = write 0 in
    inputs.wr := Bits.gnd;
    inputs.a := Bits.of_int_trunc ~width:16 0;
    inputs.b := Bits.of_int_trunc ~width:16 0;
    Cyclesim.cycle sim;
    inputs.rd := Bits.vdd;
    let rd_count = ref 0 in
    let timeout = ref 100 in
    while !rd_count <> wr_count && !timeout <> 0 do
      if not (Bits.to_bool !(outputs.empty)) then Int.incr rd_count;
      Cyclesim.cycle sim;
      Int.decr timeout
    done;
    inputs.rd := Bits.gnd;
    Cyclesim.cycle sim;
    Cyclesim.cycle sim;
    Waveform.print ~display_width:87 ~wave_width ~display_rules waves
  ;;

  let%expect_test "typed fifo fill then empty" =
    let module Sim = Cyclesim.With_interface (I) (O) in
    wrap ~cut_through:false |> Sim.create |> Waveform.create |> fill_then_empty;
    [%expect
      {|
      ┌Signals───────────┐┌Waves────────────────────────────────────────────────────────────┐
      │clock             ││┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌│
      │                  ││  └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘│
      │clear             ││────┐                                                            │
      │                  ││    └───────────────────────────────────────────────────         │
      │wr                ││    ┌───────────────────┐                                        │
      │                  ││────┘                   └───────────────────────────────         │
      │rd                ││                            ┌───────────────────┐                │
      │                  ││────────────────────────────┘                   └───────         │
      │full              ││                        ┌───────┐                                │
      │                  ││────────────────────────┘       └───────────────────────         │
      │empty             ││────────┐                                       ┌───────         │
      │                  ││        └───────────────────────────────────────┘                │
      │                  ││────┬───┬───┬───┬───┬───┬───────────────────────────────         │
      │a                 ││ 0  │10 │20 │30 │40 │50 │0                                       │
      │                  ││────┴───┴───┴───┴───┴───┴───────────────────────────────         │
      │                  ││────┬───┬───┬───┬───┬───┬───────────────────────────────         │
      │b                 ││ 0  │140│130│120│110│100│0                                       │
      │                  ││────┴───┴───┴───┴───┴───┴───────────────────────────────         │
      │overflow          ││                                                                 │
      │                  ││────────────────────────────────────────────────────────         │
      │                  ││────────┬───────────────────────┬───┬───┬───┬───┬───────         │
      │q_field_a         ││ 0      │10                     │20 │30 │40 │50 │20              │
      │                  ││────────┴───────────────────────┴───┴───┴───┴───┴───────         │
      │                  ││────────┬───────────────────────┬───┬───┬───┬───┬───────         │
      │q_field_b         ││ 0      │140                    │130│120│110│100│130             │
      │                  ││────────┴───────────────────────┴───┴───┴───┴───┴───────         │
      │read_when_empty   ││                                                                 │
      │                  ││────────────────────────────────────────────────────────         │
      │valid             ││        ┌───────────────────────────────────────┐                │
      │                  ││────────┘                                       └───────         │
      └──────────────────┘└─────────────────────────────────────────────────────────────────┘
      |}]
  ;;

  let%expect_test "typed fifo fill then empty (cut through) " =
    let module Sim = Cyclesim.With_interface (I) (O) in
    wrap ~cut_through:true |> Sim.create |> Waveform.create |> fill_then_empty;
    [%expect
      {|
      ┌Signals───────────┐┌Waves────────────────────────────────────────────────────────────┐
      │clock             ││┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌│
      │                  ││  └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘│
      │clear             ││────┐                                                            │
      │                  ││    └───────────────────────────────────────────────────         │
      │wr                ││    ┌───────────────────┐                                        │
      │                  ││────┘                   └───────────────────────────────         │
      │rd                ││                            ┌───────────────────┐                │
      │                  ││────────────────────────────┘                   └───────         │
      │full              ││                        ┌───────┐                                │
      │                  ││────────────────────────┘       └───────────────────────         │
      │empty             ││────────┐                                       ┌───────         │
      │                  ││        └───────────────────────────────────────┘                │
      │                  ││────┬───┬───┬───┬───┬───┬───────────────────────────────         │
      │a                 ││ 0  │10 │20 │30 │40 │50 │0                                       │
      │                  ││────┴───┴───┴───┴───┴───┴───────────────────────────────         │
      │                  ││────┬───┬───┬───┬───┬───┬───────────────────────────────         │
      │b                 ││ 0  │140│130│120│110│100│0                                       │
      │                  ││────┴───┴───┴───┴───┴───┴───────────────────────────────         │
      │overflow          ││                                                                 │
      │                  ││────────────────────────────────────────────────────────         │
      │                  ││────┬───────────────────────────┬───┬───┬───┬───┬───────         │
      │q_field_a         ││ 0  │10                         │20 │30 │40 │50 │0               │
      │                  ││────┴───────────────────────────┴───┴───┴───┴───┴───────         │
      │                  ││────┬───────────────────────────┬───┬───┬───┬───┬───────         │
      │q_field_b         ││ 0  │140                        │130│120│110│100│0               │
      │                  ││────┴───────────────────────────┴───┴───┴───┴───┴───────         │
      │read_when_empty   ││                                                                 │
      │                  ││────────────────────────────────────────────────────────         │
      │valid             ││    ┌───────────────────────────────────────────┐                │
      │                  ││────┘                                           └───────         │
      └──────────────────┘└─────────────────────────────────────────────────────────────────┘
      |}]
  ;;

  let%expect_test "typed fifo fill while reading" =
    let module Sim = Cyclesim.With_interface (I) (O) in
    wrap ~cut_through:false |> Sim.create |> Waveform.create |> fill_while_reading;
    [%expect
      {|
      ┌Signals───────────┐┌Waves────────────────────────────────────────────────────────────┐
      │clock             ││┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌│
      │                  ││  └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘│
      │clear             ││────┐                                                            │
      │                  ││    └───────────────────────────────────────────────────         │
      │wr                ││    ┌───────────────────────────────────────┐                    │
      │                  ││────┘                                       └───────────         │
      │rd                ││    ┌───────────────────────────────────────────────────         │
      │                  ││────┘                                                            │
      │full              ││                                                                 │
      │                  ││────────────────────────────────────────────────────────         │
      │empty             ││────────┐                                       ┌───────         │
      │                  ││        └───────────────────────────────────────┘                │
      │                  ││────┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───────────         │
      │a                 ││ 0  │10 │20 │30 │40 │50 │60 │70 │80 │90 │100│0                   │
      │                  ││────┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───────────         │
      │                  ││────┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───────────         │
      │b                 ││ 0  │140│130│120│110│100│90 │80 │70 │60 │50 │0                   │
      │                  ││────┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───────────         │
      │overflow          ││                                                                 │
      │                  ││────────────────────────────────────────────────────────         │
      │                  ││────────┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───────         │
      │q_field_a         ││ 0      │10 │20 │30 │40 │50 │60 │70 │80 │90 │100│0               │
      │                  ││────────┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───────         │
      │                  ││────────┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───────         │
      │q_field_b         ││ 0      │140│130│120│110│100│90 │80 │70 │60 │50 │0               │
      │                  ││────────┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───────         │
      │read_when_empty   ││    ┌───┐                                       ┌───────         │
      │                  ││────┘   └───────────────────────────────────────┘                │
      │valid             ││        ┌───────────────────────────────────────┐                │
      │                  ││────────┘                                       └───────         │
      └──────────────────┘└─────────────────────────────────────────────────────────────────┘
      |}]
  ;;

  let%expect_test "typed fifo fill while reading (cut through)" =
    let module Sim = Cyclesim.With_interface (I) (O) in
    wrap ~cut_through:true |> Sim.create |> Waveform.create |> fill_while_reading;
    [%expect
      {|
      ┌Signals───────────┐┌Waves────────────────────────────────────────────────────────────┐
      │clock             ││┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌│
      │                  ││  └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘│
      │clear             ││────┐                                                            │
      │                  ││    └───────────────────────────────────────────────────         │
      │wr                ││    ┌───────────────────────────────────────┐                    │
      │                  ││────┘                                       └───────────         │
      │rd                ││    ┌───────────────────────────────────────────────────         │
      │                  ││────┘                                                            │
      │full              ││                                                                 │
      │                  ││────────────────────────────────────────────────────────         │
      │empty             ││────────────────────────────────────────────────────────         │
      │                  ││                                                                 │
      │                  ││────┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───────────         │
      │a                 ││ 0  │10 │20 │30 │40 │50 │60 │70 │80 │90 │100│0                   │
      │                  ││────┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───────────         │
      │                  ││────┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───────────         │
      │b                 ││ 0  │140│130│120│110│100│90 │80 │70 │60 │50 │0                   │
      │                  ││────┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───────────         │
      │overflow          ││                                                                 │
      │                  ││────────────────────────────────────────────────────────         │
      │                  ││────┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───────────         │
      │q_field_a         ││ 0  │10 │20 │30 │40 │50 │60 │70 │80 │90 │100│0                   │
      │                  ││────┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───────────         │
      │                  ││────┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───────────         │
      │q_field_b         ││ 0  │140│130│120│110│100│90 │80 │70 │60 │50 │0                   │
      │                  ││────┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───────────         │
      │read_when_empty   ││                                            ┌───────────         │
      │                  ││────────────────────────────────────────────┘                    │
      │valid             ││    ┌───────────────────────────────────────┐                    │
      │                  ││────┘                                       └───────────         │
      └──────────────────┘└─────────────────────────────────────────────────────────────────┘
      |}]
  ;;
end
